package service

import (
	"context"
	"fmt"
	"go.uber.org/zap"
	"math/rand"
	"webook/internal/repository"
	"webook/internal/service/sms"
)

var (
	ErrCodeSendTooMany   = repository.ErrCodeSendTooMany
	ErrCodeVerifyTooMany = repository.ErrCodeVerifyTooMany
)

type CodeService interface {
	Send(ctx context.Context, biz string, phone string) error
	Verify(ctx context.Context, biz string, phone string, expectedCode string) (bool, error)
}

type SmsCodeService struct {
	repo   repository.CodeRepository
	smsSvc sms.Service
}

func NewSmsCodeService(r repository.CodeRepository, smsSvc sms.Service) CodeService {
	return &SmsCodeService{
		repo:   r,
		smsSvc: smsSvc,
	}
}

func (svc *SmsCodeService) Send(ctx context.Context, biz string, phone string) error {
	// 生成6位随机验证码
	code := svc.generateCode()
	err := svc.repo.Store(ctx, svc.key(biz, phone), code)
	if err == repository.ErrCodeSendTooMany {
		return ErrCodeSendTooMany
	}
	if err == repository.ErrCodeVerifyTooMany {
		// TODO: 验证次数太频繁（不合理）监控告警
		return ErrCodeVerifyTooMany
	}
	if err != nil {
		return err
	}
	// TODO: 发送短信
	// 调用第三方服务记录日志
	zap.L().Debug("调用第三方短信服务")
	svc.smsSvc.Send(ctx, "", "", code)
	return nil
}

func (svc *SmsCodeService) Verify(ctx context.Context, biz string, phone string, expectedCode string) (bool, error) {
	verifyRes, err := svc.repo.Verify(ctx, svc.key(biz, phone), expectedCode)
	if err == repository.ErrCodeVerifyTooMany {
		// TODO: 监控告警
		return false, ErrCodeVerifyTooMany
	}
	return verifyRes, err
}

func (svc *SmsCodeService) generateCode() string {
	// 随机生成 0 - 999999
	randNum := rand.Intn(1000000)
	return fmt.Sprintf("%06d", randNum)
}

func (svc *SmsCodeService) key(biz string, phone string) string {
	return fmt.Sprintf("code:%s:%s", biz, phone)
}
